List of TSX Issuers

Goals

  • Build stock indices from TSX Issuers related to Construction and Real Estate

Notes

rm(list=ls())
library("readxl")
library(quantmod)
library(dplyr)
library(ggplot2)
#library(tidyr)

I. Loading and Preprocessing of Excel file

The file below was downloaded 26/10/2020 from the TSX website above. File contains first some rows with non-relevant information to skip

issuers <- read_excel(paste("../../../data_tmp/tsx-andamp-tsxv-listed", 
                            "-companies-2020-10-16-en-1.xlsx", sep=""), 
                      sheet=2, skip=6)

-
/
                                                                                                                                                
colnames(issuers) <- lapply(str_replace_all(colnames(issuers), "[\r\n -$\\(\\)\\-]", "_"), FUN=tolower)
issuers <- issuers %>% filter(real_estate_sub_sector != 
                      "Real Estate Operating Companies")
real_estate <- filter(issuers, !is.na(issuers[, 'real_estate_sub_sector']))[,  c("real_estate_sub_sector", "name", "root__ticker", "market_cap__c____30_september_2020")]
head(real_estate)

Download of Stocks based on Tickers

get_stockdata <- function(stock_name_root) {
  out <- try ({
    stock_name <- paste(stock_name_root, "-UN.TO", sep="")
    stock <- getSymbols(stock_name, src = "yahoo", auto.assign = FALSE) 
    # calculate monthly returns instead of using all stock data
    stock = monthlyReturn(stock)
    colnames(stock) <- sapply(colnames(stock), function (colstock) str_split(colstock, "\\.")[[1]][length(str_split(colstock, "\\.")[[1]])])
    stock <- data.frame(date=index(stock), coredata(stock))
    stock$stock_name <- rep(stock_name, nrow(stock))
    stock$stock_name_root <- rep(stock_name_root, nrow(stock))
    stock
  })
  
  # if stock is not available as "[stockname]-UN.TO", try "[stockname"].TO"
  if (class(out) == "try-error") {
  
    out <- try ({
      stock_name <- paste(stock_name_root, ".TO", sep="")
      stock <- getSymbols(stock_name, src = "yahoo", auto.assign = FALSE) 
    # calculate monthly returns instead of using all stock data
      stock = monthlyReturn(stock)
      colnames(stock) <- sapply(colnames(stock), function (colstock) str_split(colstock, "\\.")[[1]][length(str_split(colstock, "\\.")[[1]])])
      stock <- data.frame(date=index(stock), coredata(stock))
      stock$stock_name <- rep(stock_name, nrow(stock))
      stock$stock_name_root <- rep(stock_name_root, nrow(stock))
      stock
    })
  }
  
  out
  }
start.time <- Sys.time()
get_stock_series <- lapply(real_estate$root__ticker, get_stockdata)
AP-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataHOT-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataAX-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataAPR-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataBEI-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataBRE-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "BRE-UN.TO", env = <environment>,  : 
  Unable to import “BRE-UN.TO”.
BRE-UN.TO download failed after two attempts. Error message:
HTTP error 404.
BRE.TO download failed; trying again.BPO-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "BPO-UN.TO", env = <environment>,  : 
  Unable to import “BPO-UN.TO”.
BPO-UN.TO download failed after two attempts. Error message:
HTTP error 404.
BPO.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "BPO.TO", env = <environment>, verbose = FALSE,  : 
  Unable to import “BPO.TO”.
BPO.TO download failed after two attempts. Error message:
HTTP error 404.
BPY-UN.TO download failed; trying again.BPY-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataHOM-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataBTB-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataCAR-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataCSH-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataCHP-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataCUF-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataCRR-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataCRT-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataDRA-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataDIR-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataWarning in for (i in seq_along(specs)) { :
  closing unused connection 10 (https://query2.finance.yahoo.com/v7/finance/download/BPY-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=0ZaCTBmwUIT)
Warning in for (i in seq_along(specs)) { :
  closing unused connection 9 (https://query2.finance.yahoo.com/v7/finance/download/BPO.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=0ZaCTBmwUIT)
Warning in for (i in seq_along(specs)) { :
  closing unused connection 8 (https://query1.finance.yahoo.com/v7/finance/download/BPO.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=5lX0EHTTCJ5)
Warning in for (i in seq_along(specs)) { :
  closing unused connection 7 (https://query2.finance.yahoo.com/v7/finance/download/BPO-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=5lX0EHTTCJ5)
Warning in for (i in seq_along(specs)) { :
  closing unused connection 6 (https://query1.finance.yahoo.com/v7/finance/download/BPO-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=ECXbPudmyxB)
Warning in for (i in seq_along(specs)) { :
  closing unused connection 5 (https://query1.finance.yahoo.com/v7/finance/download/BRE.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=mhkqOB7.Lhz)
Warning in for (i in seq_along(specs)) { :
  closing unused connection 4 (https://query1.finance.yahoo.com/v7/finance/download/BRE-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=mhkqOB7.Lhz)
Warning in for (i in seq_along(specs)) { :
  closing unused connection 3 (https://query1.finance.yahoo.com/v7/finance/download/BRE-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=X/RIh7lRHJt)
D-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataDRM-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "DRM-UN.TO", env = <environment>,  : 
  Unable to import “DRM-UN.TO”.
DRM-UN.TO download failed after two attempts. Error message:
HTTP error 404.
DRM.TO download failed; trying again.ERE-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "ERE-UN.TO", env = <environment>,  : 
  Unable to import “ERE-UN.TO”.
ERE-UN.TO download failed after two attempts. Error message:
HTTP error 404.
ERE.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "ERE.TO", env = <environment>, verbose = FALSE,  : 
  Unable to import “ERE.TO”.
ERE.TO download failed after two attempts. Error message:
HTTP error 404.
EXE-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "EXE-UN.TO", env = <environment>,  : 
  Unable to import “EXE-UN.TO”.
EXE-UN.TO download failed after two attempts. Error message:
HTTP error 404.
EXE.TO download failed; trying again.FCR-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataFSV-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "FSV-UN.TO", env = <environment>,  : 
  Unable to import “FSV-UN.TO”.
FSV-UN.TO download failed after two attempts. Error message:
HTTP error 404.
FSV.TO download failed; trying again.GDC-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "GDC-UN.TO", env = <environment>,  : 
  Unable to import “GDC-UN.TO”.
GDC-UN.TO download failed after two attempts. Error message:
HTTP error 404.
GDC.TO download failed; trying again.HR-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataINO-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataIIP-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataIVQ-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "IVQ-UN.TO", env = <environment>,  : 
  Unable to import “IVQ-UN.TO”.
IVQ-UN.TO download failed after two attempts. Error message:
HTTP error 404.
IVQ.TO download failed; trying again.DR-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "DR-UN.TO", env = <environment>, verbose = FALSE,  : 
  Unable to import “DR-UN.TO”.
DR-UN.TO download failed after two attempts. Error message:
HTTP error 404.
DR.TO download failed; trying again.MRD-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "MRD-UN.TO", env = <environment>,  : 
  Unable to import “MRD-UN.TO”.
MRD-UN.TO download failed after two attempts. Error message:
HTTP error 404.
MRD.TO download failed; trying again.MR-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataMI-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataMRC-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "MRC-UN.TO", env = <environment>,  : 
  Unable to import “MRC-UN.TO”.
MRC-UN.TO download failed after two attempts. Error message:
HTTP error 404.
MRC.TO download failed; trying again.MRG-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataWarning in for (i in (1L:cols)[do]) { :
  closing unused connection 30 (https://query1.finance.yahoo.com/v7/finance/download/MRC.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=0GiFxYmxEkw)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 29 (https://query1.finance.yahoo.com/v7/finance/download/MRC-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=0GiFxYmxEkw)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 28 (https://query1.finance.yahoo.com/v7/finance/download/MRC-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=zMcc.8LskN9)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 27 (https://query2.finance.yahoo.com/v7/finance/download/MRD.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=aaFMiwLkm1s)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 26 (https://query2.finance.yahoo.com/v7/finance/download/MRD-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=aaFMiwLkm1s)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 25 (https://query1.finance.yahoo.com/v7/finance/download/MRD-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=CmtUHRy.Ydp)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 24 (https://query1.finance.yahoo.com/v7/finance/download/DR.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=g/R3XudJb6K)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 23 (https://query2.finance.yahoo.com/v7/finance/download/DR-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=g/R3XudJb6K)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 22 (https://query1.finance.yahoo.com/v7/finance/download/DR-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=d./AWL6Hl76)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 21 (https://query1.finance.yahoo.com/v7/finance/download/IVQ.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=fEhNP1RI7NY)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 20 (https://query1.finance.yahoo.com/v7/finance/download/IVQ-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=fEhNP1RI7NY)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 19 (https://query1.finance.yahoo.com/v7/finance/download/IVQ-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=8502sNx8Cz7)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 18 (https://query2.finance.yahoo.com/v7/finance/download/GDC.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=/dexIhqywnE)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 17 (https://query2.finance.yahoo.com/v7/finance/download/GDC-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=/dexIhqywnE)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 16 (https://query2.finance.yahoo.com/v7/finance/download/GDC-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=8iVOnZKZ6K2)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 15 (https://query2.finance.yahoo.com/v7/finance/download/FSV.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=DIb5a5EXjF8)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 14 (https://query2.finance.yahoo.com/v7/finance/download/FSV-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=DIb5a5EXjF8)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 13 (https://query1.finance.yahoo.com/v7/finance/download/FSV-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=./UknJ2Aonl)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 12 (https://query1.finance.yahoo.com/v7/finance/download/EXE.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=m9qQuPX5590)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 11 (https://query1.finance.yahoo.com/v7/finance/download/EXE-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=m9qQuPX5590)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 10 (https://query2.finance.yahoo.com/v7/finance/download/EXE-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=/6U1XInyc2o)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 9 (https://query1.finance.yahoo.com/v7/finance/download/ERE.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=/6U1XInyc2o)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 8 (https://query2.finance.yahoo.com/v7/finance/download/ERE.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=A3KYuYaARSl)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 7 (https://query2.finance.yahoo.com/v7/finance/download/ERE-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=A3KYuYaARSl)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 6 (https://query2.finance.yahoo.com/v7/finance/download/ERE-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=jIi9hGssuqJ)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 5 (https://query2.finance.yahoo.com/v7/finance/download/DRM.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=WCJwgsuLizu)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 4 (https://query2.finance.yahoo.com/v7/finance/download/DRM-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=WCJwgsuLizu)
Warning in for (i in (1L:cols)[do]) { :
  closing unused connection 3 (https://query2.finance.yahoo.com/v7/finance/download/DRM-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=dC4DdeZwFxR)
MRT-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataNVU-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataNWH-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataPLZ-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataPRV-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataREI-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataSIA-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "SIA-UN.TO", env = <environment>,  : 
  Unable to import “SIA-UN.TO”.
SIA-UN.TO download failed after two attempts. Error message:
HTTP error 404.
SIA.TO download failed; trying again.SIA.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataSGR-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "SGR-UN.TO", env = <environment>,  : 
  Unable to import “SGR-UN.TO”.
SGR-UN.TO download failed after two attempts. Error message:
HTTP error 404.
SGR.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "SGR.TO", env = <environment>, verbose = FALSE,  : 
  Unable to import “SGR.TO”.
SGR.TO download failed after two attempts. Error message:
HTTP error 404.
SOT-UN.TO download failed; trying again.SOT-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataSRU-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataSMU-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataTNT-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataWFC-UN.TO download failed; trying again.Error in getSymbols.yahoo(Symbols = "WFC-UN.TO", env = <environment>,  : 
  Unable to import “WFC-UN.TO”.
WFC-UN.TO download failed after two attempts. Error message:
HTTP error 404.
WFC.TO download failed; trying again.WIR-UN.TO contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.missing values removed from dataWarning in for (i in seq_len(n)) { :
  closing unused connection 13 (https://query2.finance.yahoo.com/v7/finance/download/WFC.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=MKtdgATEPNQ)
Warning in for (i in seq_len(n)) { :
  closing unused connection 12 (https://query2.finance.yahoo.com/v7/finance/download/WFC-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=MKtdgATEPNQ)
Warning in for (i in seq_len(n)) { :
  closing unused connection 11 (https://query2.finance.yahoo.com/v7/finance/download/WFC-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=R79T334MbmJ)
Warning in for (i in seq_len(n)) { :
  closing unused connection 10 (https://query2.finance.yahoo.com/v7/finance/download/SOT-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=JO0xh0sfLAF)
Warning in for (i in seq_len(n)) { :
  closing unused connection 9 (https://query1.finance.yahoo.com/v7/finance/download/SGR.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=JO0xh0sfLAF)
Warning in for (i in seq_len(n)) { :
  closing unused connection 8 (https://query1.finance.yahoo.com/v7/finance/download/SGR.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=XAbGyJ59DB.)
Warning in for (i in seq_len(n)) { :
  closing unused connection 7 (https://query1.finance.yahoo.com/v7/finance/download/SGR-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=XAbGyJ59DB.)
Warning in for (i in seq_len(n)) { :
  closing unused connection 6 (https://query2.finance.yahoo.com/v7/finance/download/SGR-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=qOaFXwzm/vq)
Warning in for (i in seq_len(n)) { :
  closing unused connection 5 (https://query2.finance.yahoo.com/v7/finance/download/SIA.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=6YpCtzUSH5v)
Warning in for (i in seq_len(n)) { :
  closing unused connection 4 (https://query2.finance.yahoo.com/v7/finance/download/SIA-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=6YpCtzUSH5v)
Warning in for (i in seq_len(n)) { :
  closing unused connection 3 (https://query2.finance.yahoo.com/v7/finance/download/SIA-UN.TO?period1=1167609600&period2=1604448000&interval=1d&events=history&crumb=zEEkX.Nkr/X)
print(paste("total download time :", Sys.time() - start.time, "s"))
[1] "total download time : 1.76225287914276 s"

Check downloads

downloaded <- list()
stock_series <- list()
j = 1
k = 1
for (i in 1:length(get_stock_series)) {
  if (class(get_stock_series[[i]]) == "try-error") {
    #missing_data_log[[k]] <- get_stock_series[[i]]
    print(get_stock_series[[i]])
    downloaded[[i]] <- FALSE
  } else {
    downloaded[[i]] <- TRUE
    stock_series[[j]] <- get_stock_series[[i]]
    j <- j + 1
  }
}
[1] "Error in getSymbols.yahoo(Symbols = \"BPO.TO\", env = <environment>, verbose = FALSE,  : \n  Unable to import “BPO.TO”.\nBPO.TO download failed after two attempts. Error message:\nHTTP error 404.\n"
attr(,"class")
[1] "try-error"
attr(,"condition")
<simpleError in getSymbols.yahoo(Symbols = "BPO.TO", env = <environment>, verbose = FALSE,     warnings = TRUE, auto.assign = FALSE, .has1sym. = TRUE): Unable to import “BPO.TO”.
BPO.TO download failed after two attempts. Error message:
HTTP error 404.>
[1] "Error in getSymbols.yahoo(Symbols = \"ERE.TO\", env = <environment>, verbose = FALSE,  : \n  Unable to import “ERE.TO”.\nERE.TO download failed after two attempts. Error message:\nHTTP error 404.\n"
attr(,"class")
[1] "try-error"
attr(,"condition")
<simpleError in getSymbols.yahoo(Symbols = "ERE.TO", env = <environment>, verbose = FALSE,     warnings = TRUE, auto.assign = FALSE, .has1sym. = TRUE): Unable to import “ERE.TO”.
ERE.TO download failed after two attempts. Error message:
HTTP error 404.>
[1] "Error in getSymbols.yahoo(Symbols = \"SGR.TO\", env = <environment>, verbose = FALSE,  : \n  Unable to import “SGR.TO”.\nSGR.TO download failed after two attempts. Error message:\nHTTP error 404.\n"
attr(,"class")
[1] "try-error"
attr(,"condition")
<simpleError in getSymbols.yahoo(Symbols = "SGR.TO", env = <environment>, verbose = FALSE,     warnings = TRUE, auto.assign = FALSE, .has1sym. = TRUE): Unable to import “SGR.TO”.
SGR.TO download failed after two attempts. Error message:
HTTP error 404.>
real_estate['downloaded'] <- unlist(list(downloaded))

Analysis of missing data

A small amount of stocks were not downloaded/are not available

table(real_estate$downloaded)

FALSE  TRUE 
    3    46 

II. Analysis of stocks Properties

stock_series <- bind_rows(stock_series)
```r
real_estate[ !real_estate$downloaded, ]

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


add sub-sector information to stocks

<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuc3RvY2tfc2VyaWVzIDwtIG1lcmdlKHN0b2NrX3NlcmllcywgcmVhbF9lc3RhdGUsIGJ5Lng9XCJzdG9ja19uYW1lX3Jvb3RcIiwgYnkueT1cInJvb3RfX3RpY2tlclwiLCBhbGw9RkFMU0UpXG5oZWFkKHN0b2NrX3NlcmllcywgMilcbmBgYCJ9 -->

```r
stock_series <- merge(stock_series, real_estate, by.x="stock_name_root", by.y="root__ticker", all=FALSE)
head(stock_series, 2)
table(real_estate[real_estate$downloaded, ]$real_estate_sub_sector)

                         Diversified Industrial/Office/Retail/Residential Real Estate Development and Services 
                                   7                                   30                                    3 
                         Specialized 
                                   6 

1. Category: Diversified

Most companies go back to 2007 but those with the largest market cap go back only to 2012. Fair amount of distribution.

stock_series_stats_div <- stock_series %>% 
  filter(real_estate_sub_sector=="Diversified") %>%
  group_by(stock_name_root) %>%
      summarize(
        min = min(date, na.rm=TRUE),
        max = max(date, na.rm=TRUE),
        real_estate_sub_sector = unique(real_estate_sub_sector),
        market_cap__c____30_september_2020 = 
          max(market_cap__c____30_september_2020),
        name = unique(name),
        .groups = "keep"
      )
stock_series_stats_div$market_cap_fraction <- 
  stock_series_stats_div$market_cap__c____30_september_2020/sum(stock_series_stats_div$market_cap__c____30_september_2020)
stock_series_stats_div$real_estate_sub_sector <- NULL
stock_series_stats_div
p <- ggplot(data = filter(stock_series, real_estate_sub_sector == "Diversified")) + 
              geom_line(aes(x = as.Date(date), y = returns, group=stock_name_root, color=name, linetype=name)) +
                labs(title = "Category - Diversified",
                   x = "reference month", y = "monthly stock returns", 
                            group= "Ticker", color= "Ticker")
ggplotly(p, width=880, height=450)
`group_by_()` is deprecated as of dplyr 0.7.0.
Please use `group_by()` instead.
See vignette('programming') for more help
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.

To calculate the index for the category I move the stock tickers into theor own column which allows easier calculations later on. Each row corresponds to one unique month

stock_series_div <- tidyr::pivot_wider(filter(stock_series, real_estate_sub_sector == "Diversified")[, c("date", "stock_name_root", "returns")],
                   names_from = stock_name_root, values_from = returns)
# ensures that if stock is not available this month, there is a 0
stock_series_div[is.na(stock_series_div)] <- 0
head(stock_series_div, 2)
# get market caps for stock tickers of category.
market_cap <- stock_series_stats_div$market_cap__c____30_september_2020

create_index_value <- function(x) {

  # create sum of market cap for all stocks existing this month
  missing_value_flag <- x != 0
  monthly_norm_factor <-  sum(market_cap[missing_value_flag])

  # index are stocks x weighted by normalized market cap   
  monthly_index <- sum((x * market_cap) / monthly_norm_factor)
  monthly_index
}
stock_series_div$index <- apply(stock_series_div[, stock_series_stats_div$stock_name_root], 1, create_index_value)
head(stock_series_div)
p <- ggplot(data = stock_series_div) + 
              geom_line(aes(x = as.Date(date), y = index)) +
                labs(title = " Category -Diversified - Index",
                   x = "reference month", y = "index", 
                            group= "Ticker", color= "Ticker")
ggplotly(p, width=880, height=450)
head(stock_series_div)
filter(stock_series, real_estate_sub_sector == "Diversified")

2. Category: Specialized

The companies with a largest market capitalization exist also the longest. If we would weight according to capitalization, then only two companies would dominate an categorical indicator.

stock_series_stats_spec <- stock_series %>% 
  filter(real_estate_sub_sector=="Specialized") %>%
  group_by(stock_name_root) %>%
      summarize(
        min = min(date, na.rm=TRUE),
        max = max(date, na.rm=TRUE),
        real_estate_sub_sector = unique(real_estate_sub_sector),
        market_cap__c____30_september_2020 = 
          max(market_cap__c____30_september_2020),
        name = unique(name),
        .groups = "keep"
      )
stock_series_stats_spec$market_cap_fraction <- 
  stock_series_stats_spec$market_cap__c____30_september_2020/sum(stock_series_stats_spec$market_cap__c____30_september_2020)
stock_series_stats_spec$real_estate_sub_sector <- NULL
stock_series_stats_spec
p <- ggplot(data = filter(stock_series, real_estate_sub_sector == "Specialized")) + 
              geom_line(aes(x = as.Date(date), y = returns, group=stock_name_root, color=name, linetype=name)) +
                labs(title = "Category - Specialized",
                   x = "reference month", y = "close stock value", 
                            group= "Ticker", color= "Ticker")
ggplotly(p, width=80, height=450)

3. Category: Real Estate Development and Services

All 3 companies exist for a longer time at the stock market and have a similar market cap. One company would dominate a categorical indicator with 50%.

stock_series_stats_real <- stock_series %>% 
  filter(real_estate_sub_sector=="Real Estate Development and Services") %>%
  group_by(stock_name_root) %>%
      summarize(
        min = min(date, na.rm=TRUE),
        max = max(date, na.rm=TRUE),
        real_estate_sub_sector = unique(real_estate_sub_sector),
        market_cap__c____30_september_2020 = 
          max(market_cap__c____30_september_2020),
        name = unique(name),
        .groups = "keep"
      )
stock_series_stats_real$market_cap_fraction <- 
  stock_series_stats_real$market_cap__c____30_september_2020/sum(stock_series_stats_real$market_cap__c____30_september_2020)
stock_series_stats_real$real_estate_sub_sector <- NULL
stock_series_stats_real
p <- ggplot(data = filter(stock_series, real_estate_sub_sector == "Real Estate Development and Services")) + 
              geom_line(aes(x = as.Date(date), y = returns, group=stock_name_root, color=name, linetype=name)) +
                labs(title = "Category - Real Estate Development and Services",
                   x = "reference month", y = "close stock value", 
                            group= "Ticker", color= "Ticker")
ggplotly(p, width=780, height=450)

4. Category: Industrial/Office/Retail/Residential

stock_series_stats_ind <- stock_series %>% 
  filter(real_estate_sub_sector=="Industrial/Office/Retail/Residential") %>%
  group_by(stock_name_root) %>%
      summarize(
        min = min(date, na.rm=TRUE),
        max = max(date, na.rm=TRUE),
        real_estate_sub_sector = unique(real_estate_sub_sector),
        market_cap__c____30_september_2020 = 
          max(market_cap__c____30_september_2020),
        .groups = "keep"
      )
stock_series_stats_ind$market_cap_fraction <- 
  stock_series_stats_ind$market_cap__c____30_september_2020/sum(stock_series_stats_ind$market_cap__c____30_september_2020)
stock_series_stats_ind$real_estate_sub_sector <- NULL
stock_series_stats_ind

Top companies in company for market cap indicates that the market cap is fairly distributed and there may be a less dependency of a categorical indicator on individual companies.


head(stock_series_stats_ind %>% arrange(across(market_cap_fraction, desc)), 10)
p <- ggplot(data = filter(stock_series, real_estate_sub_sector == "Industrial/Office/Retail/Residential")) + 
              geom_line(aes(x = as.Date(date), y = returns, group=stock_name_root, color=name, linetype=name)) +
                labs(title = "Category - Industrial/Office/Retail/Residential",
                   x = "reference month", y = "close stock value", 
                            group= "Ticker", color= "Ticker")
ggplotly(p, width=880, height=450)

5. All Categories

stock_series_stats_all <- stock_series %>% 
  group_by(stock_name_root) %>%
      summarize(
        min = min(date, na.rm=TRUE),
        max = max(date, na.rm=TRUE),
        real_estate_sub_sector = unique(real_estate_sub_sector),
        market_cap__c____30_september_2020 = 
          max(market_cap__c____30_september_2020),
        .groups = "keep"
      )
stock_series_stats_all$market_cap_fraction <- 
  stock_series_stats_all$market_cap__c____30_september_2020/sum(stock_series_stats_all$market_cap__c____30_september_2020)
stock_series_stats_all$real_estate_sub_sector <- NULL
stock_series_stats_all

Fairly well distributed.

head(stock_series_stats_all %>% arrange(across(market_cap_fraction, desc)), 10)
p <- ggplot(data = stock_series) + 
              geom_line(aes(x = as.Date(date), y = returns, group=stock_name_root, alpha=0.2)) +
                labs(title = "All tickers",
                   x = "reference month", y = "close stock value", 
                            group= "Ticker", color= "Ticker")
ggplotly(p, width=880, height=450)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBMaXN0IG9mIFRTWCBJc3N1ZXJzCgojIyMgR29hbHMKCiogQnVpbGQgc3RvY2sgaW5kaWNlcyBmcm9tIFRTWCBJc3N1ZXJzIHJlbGF0ZWQgdG8gQ29uc3RydWN0aW9uIGFuZCBSZWFsIEVzdGF0ZQoKIyMjIE5vdGVzCgoqIERhdGEgZGlyZWN0bHkgZnJvbSBUU1ggYXQgaHR0cHM6Ly93d3cudHN4LmNvbS9saXN0aW5ncy9jdXJyZW50LW1hcmtldC1zdGF0aXN0aWNzCmFuZCBzcGVjaWZpY2FsbHkuIAoqIFdlIHdhbnQgdG8gaW5nZXN0IHRoZSBwcm9kdWNlZCBpbmRpY2VzIGF0IHNvbWUgcG9pbnQuCgpgYGB7cn0Kcm0obGlzdD1scygpKQpgYGAKCgpgYGB7cn0KbGlicmFyeSgicmVhZHhsIikKbGlicmFyeShxdWFudG1vZCkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQojbGlicmFyeSh0aWR5cikKYGBgCgojIyBJLiBMb2FkaW5nIGFuZCBQcmVwcm9jZXNzaW5nIG9mIEV4Y2VsIGZpbGUKCgpUaGUgZmlsZSBiZWxvdyB3YXMgZG93bmxvYWRlZCAyNi8xMC8yMDIwIGZyb20gdGhlIFRTWCB3ZWJzaXRlIGFib3ZlLgpGaWxlIGNvbnRhaW5zIGZpcnN0IHNvbWUgcm93cyB3aXRoIG5vbi1yZWxldmFudCBpbmZvcm1hdGlvbiB0byBza2lwCmBgYHtyfQppc3N1ZXJzIDwtIHJlYWRfZXhjZWwocGFzdGUoIi4uLy4uLy4uL2RhdGFfdG1wL3RzeC1hbmRhbXAtdHN4di1saXN0ZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICItY29tcGFuaWVzLTIwMjAtMTAtMTYtZW4tMS54bHN4Iiwgc2VwPSIiKSwgCiAgICAgICAgICAgICAgICAgICAgICBzaGVldD0yLCBza2lwPTYpCmBgYAoKCmBgYHtyfQpjb2xuYW1lcyhpc3N1ZXJzKSA8LSBsYXBwbHkoc3RyX3JlcGxhY2VfYWxsKGNvbG5hbWVzKGlzc3VlcnMpLCAiW1xyXG4gLSRcXChcXClcXC1dIiwgIl8iKSwgRlVOPXRvbG93ZXIpCmBgYAoKCmBgYHtyfQppc3N1ZXJzIDwtIGlzc3VlcnMgJT4lIGZpbHRlcihyZWFsX2VzdGF0ZV9zdWJfc2VjdG9yICE9IAogICAgICAgICAgICAgICAgICAgICAgIlJlYWwgRXN0YXRlIE9wZXJhdGluZyBDb21wYW5pZXMiKQpyZWFsX2VzdGF0ZSA8LSBmaWx0ZXIoaXNzdWVycywgIWlzLm5hKGlzc3VlcnNbLCAncmVhbF9lc3RhdGVfc3ViX3NlY3RvciddKSlbLCAgYygicmVhbF9lc3RhdGVfc3ViX3NlY3RvciIsICJuYW1lIiwgInJvb3RfX3RpY2tlciIsICJtYXJrZXRfY2FwX19jX19fXzMwX3NlcHRlbWJlcl8yMDIwIildCmBgYAoKYGBge3J9CmhlYWQocmVhbF9lc3RhdGUpCmBgYAoKCiMjIyBEb3dubG9hZCBvZiBTdG9ja3MgYmFzZWQgb24gVGlja2VycwoKCmBgYHtyfQpnZXRfc3RvY2tkYXRhIDwtIGZ1bmN0aW9uKHN0b2NrX25hbWVfcm9vdCkgewoKICBvdXQgPC0gdHJ5ICh7CiAgICBzdG9ja19uYW1lIDwtIHBhc3RlKHN0b2NrX25hbWVfcm9vdCwgIi1VTi5UTyIsIHNlcD0iIikKICAgIHN0b2NrIDwtIGdldFN5bWJvbHMoc3RvY2tfbmFtZSwgc3JjID0gInlhaG9vIiwgYXV0by5hc3NpZ24gPSBGQUxTRSkgCgogICAgIyBjYWxjdWxhdGUgbW9udGhseSByZXR1cm5zIGluc3RlYWQgb2YgdXNpbmcgYWxsIHN0b2NrIGRhdGEKICAgIHN0b2NrID0gbW9udGhseVJldHVybihzdG9jaykKICAgIGNvbG5hbWVzKHN0b2NrKSA8LSBzYXBwbHkoY29sbmFtZXMoc3RvY2spLCBmdW5jdGlvbiAoY29sc3RvY2spIHN0cl9zcGxpdChjb2xzdG9jaywgIlxcLiIpW1sxXV1bbGVuZ3RoKHN0cl9zcGxpdChjb2xzdG9jaywgIlxcLiIpW1sxXV0pXSkKICAgIHN0b2NrIDwtIGRhdGEuZnJhbWUoZGF0ZT1pbmRleChzdG9jayksIGNvcmVkYXRhKHN0b2NrKSkKICAgIHN0b2NrJHN0b2NrX25hbWUgPC0gcmVwKHN0b2NrX25hbWUsIG5yb3coc3RvY2spKQogICAgc3RvY2skc3RvY2tfbmFtZV9yb290IDwtIHJlcChzdG9ja19uYW1lX3Jvb3QsIG5yb3coc3RvY2spKQogICAgc3RvY2sKICB9KQogIAogICMgaWYgc3RvY2sgaXMgbm90IGF2YWlsYWJsZSBhcyAiW3N0b2NrbmFtZV0tVU4uVE8iLCB0cnkgIltzdG9ja25hbWUiXS5UTyIKICBpZiAoY2xhc3Mob3V0KSA9PSAidHJ5LWVycm9yIikgewogIAogICAgb3V0IDwtIHRyeSAoewogICAgICBzdG9ja19uYW1lIDwtIHBhc3RlKHN0b2NrX25hbWVfcm9vdCwgIi5UTyIsIHNlcD0iIikKICAgICAgc3RvY2sgPC0gZ2V0U3ltYm9scyhzdG9ja19uYW1lLCBzcmMgPSAieWFob28iLCBhdXRvLmFzc2lnbiA9IEZBTFNFKSAKICAgICMgY2FsY3VsYXRlIG1vbnRobHkgcmV0dXJucyBpbnN0ZWFkIG9mIHVzaW5nIGFsbCBzdG9jayBkYXRhCiAgICAgIHN0b2NrID0gbW9udGhseVJldHVybihzdG9jaykKICAgICAgY29sbmFtZXMoc3RvY2spIDwtIHNhcHBseShjb2xuYW1lcyhzdG9jayksIGZ1bmN0aW9uIChjb2xzdG9jaykgc3RyX3NwbGl0KGNvbHN0b2NrLCAiXFwuIilbWzFdXVtsZW5ndGgoc3RyX3NwbGl0KGNvbHN0b2NrLCAiXFwuIilbWzFdXSldKQogICAgICBzdG9jayA8LSBkYXRhLmZyYW1lKGRhdGU9aW5kZXgoc3RvY2spLCBjb3JlZGF0YShzdG9jaykpCiAgICAgIHN0b2NrJHN0b2NrX25hbWUgPC0gcmVwKHN0b2NrX25hbWUsIG5yb3coc3RvY2spKQogICAgICBzdG9jayRzdG9ja19uYW1lX3Jvb3QgPC0gcmVwKHN0b2NrX25hbWVfcm9vdCwgbnJvdyhzdG9jaykpCiAgICAgIHN0b2NrCiAgICB9KQogIH0KICAKICBvdXQKICB9CmBgYAoKCmBgYHtyfQpzdGFydC50aW1lIDwtIFN5cy50aW1lKCkKZ2V0X3N0b2NrX3NlcmllcyA8LSBsYXBwbHkocmVhbF9lc3RhdGUkcm9vdF9fdGlja2VyLCBnZXRfc3RvY2tkYXRhKQpwcmludChwYXN0ZSgidG90YWwgZG93bmxvYWQgdGltZSA6IiwgU3lzLnRpbWUoKSAtIHN0YXJ0LnRpbWUsICJzIikpCmBgYAoKCkNoZWNrIGRvd25sb2FkcwpgYGB7cn0KZG93bmxvYWRlZCA8LSBsaXN0KCkKc3RvY2tfc2VyaWVzIDwtIGxpc3QoKQpqID0gMQprID0gMQpmb3IgKGkgaW4gMTpsZW5ndGgoZ2V0X3N0b2NrX3NlcmllcykpIHsKICBpZiAoY2xhc3MoZ2V0X3N0b2NrX3Nlcmllc1tbaV1dKSA9PSAidHJ5LWVycm9yIikgewogICAgI21pc3NpbmdfZGF0YV9sb2dbW2tdXSA8LSBnZXRfc3RvY2tfc2VyaWVzW1tpXV0KICAgIHByaW50KGdldF9zdG9ja19zZXJpZXNbW2ldXSkKICAgIGRvd25sb2FkZWRbW2ldXSA8LSBGQUxTRQogIH0gZWxzZSB7CiAgICBkb3dubG9hZGVkW1tpXV0gPC0gVFJVRQogICAgc3RvY2tfc2VyaWVzW1tqXV0gPC0gZ2V0X3N0b2NrX3Nlcmllc1tbaV1dCiAgICBqIDwtIGogKyAxCiAgfQp9CnJlYWxfZXN0YXRlWydkb3dubG9hZGVkJ10gPC0gdW5saXN0KGxpc3QoZG93bmxvYWRlZCkpCmBgYAoKIyMjIEFuYWx5c2lzIG9mIG1pc3NpbmcgZGF0YQoKQSBzbWFsbCBhbW91bnQgb2Ygc3RvY2tzIHdlcmUgbm90IGRvd25sb2FkZWQvYXJlIG5vdCBhdmFpbGFibGUKYGBge3J9CnRhYmxlKHJlYWxfZXN0YXRlJGRvd25sb2FkZWQpCmBgYAoKCiMjIElJLiBBbmFseXNpcyBvZiBzdG9ja3MgUHJvcGVydGllcwoKYGBge3J9CnN0b2NrX3NlcmllcyA8LSBiaW5kX3Jvd3Moc3RvY2tfc2VyaWVzKQpgYGAKCgoKYGBge3J9CmhlYWQoc3RvY2tfc2VyaWVzKQpgYGAKCmFkZCBzdWItc2VjdG9yIGluZm9ybWF0aW9uIHRvIHN0b2NrcwpgYGB7cn0Kc3RvY2tfc2VyaWVzIDwtIG1lcmdlKHN0b2NrX3NlcmllcywgcmVhbF9lc3RhdGUsIGJ5Lng9InN0b2NrX25hbWVfcm9vdCIsIAogICAgICAgICAgICAgICAgICAgICAgYnkueT0icm9vdF9fdGlja2VyIiwgYWxsPUZBTFNFKQpoZWFkKHN0b2NrX3NlcmllcywgMikKYGBgCgoKYGBge3J9CnRhYmxlKHJlYWxfZXN0YXRlW3JlYWxfZXN0YXRlJGRvd25sb2FkZWQsIF0kcmVhbF9lc3RhdGVfc3ViX3NlY3RvcikKYGBgCgojIyMgMS4gQ2F0ZWdvcnk6IERpdmVyc2lmaWVkCgpNb3N0IGNvbXBhbmllcyBnbyBiYWNrIHRvIDIwMDcgYnV0IHRob3NlIHdpdGggdGhlIGxhcmdlc3QgbWFya2V0IGNhcApnbyBiYWNrIG9ubHkgdG8gMjAxMi4gRmFpciBhbW91bnQgb2YgZGlzdHJpYnV0aW9uLgpgYGB7cn0Kc3RvY2tfc2VyaWVzX3N0YXRzX2RpdiA8LSBzdG9ja19zZXJpZXMgJT4lIAogIGZpbHRlcihyZWFsX2VzdGF0ZV9zdWJfc2VjdG9yPT0iRGl2ZXJzaWZpZWQiKSAlPiUKICBncm91cF9ieShzdG9ja19uYW1lX3Jvb3QpICU+JQogICAgICBzdW1tYXJpemUoCiAgICAgICAgbWluID0gbWluKGRhdGUsIG5hLnJtPVRSVUUpLAogICAgICAgIG1heCA9IG1heChkYXRlLCBuYS5ybT1UUlVFKSwKICAgICAgICByZWFsX2VzdGF0ZV9zdWJfc2VjdG9yID0gdW5pcXVlKHJlYWxfZXN0YXRlX3N1Yl9zZWN0b3IpLAogICAgICAgIG1hcmtldF9jYXBfX2NfX19fMzBfc2VwdGVtYmVyXzIwMjAgPSAKICAgICAgICAgIG1heChtYXJrZXRfY2FwX19jX19fXzMwX3NlcHRlbWJlcl8yMDIwKSwKICAgICAgICBuYW1lID0gdW5pcXVlKG5hbWUpLAogICAgICAgIC5ncm91cHMgPSAia2VlcCIKICAgICAgKQpzdG9ja19zZXJpZXNfc3RhdHNfZGl2JG1hcmtldF9jYXBfZnJhY3Rpb24gPC0gCiAgc3RvY2tfc2VyaWVzX3N0YXRzX2RpdiRtYXJrZXRfY2FwX19jX19fXzMwX3NlcHRlbWJlcl8yMDIwL3N1bShzdG9ja19zZXJpZXNfc3RhdHNfZGl2JG1hcmtldF9jYXBfX2NfX19fMzBfc2VwdGVtYmVyXzIwMjApCnN0b2NrX3Nlcmllc19zdGF0c19kaXYkcmVhbF9lc3RhdGVfc3ViX3NlY3RvciA8LSBOVUxMCnN0b2NrX3Nlcmllc19zdGF0c19kaXYKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTI0LCBmaWcuaGVpZ2h0PTEyfQpwIDwtIGdncGxvdChkYXRhID0gZmlsdGVyKHN0b2NrX3NlcmllcywgcmVhbF9lc3RhdGVfc3ViX3NlY3RvciA9PSAiRGl2ZXJzaWZpZWQiKSkgKyAKICAgICAgICAgICAgICBnZW9tX2xpbmUoYWVzKHggPSBhcy5EYXRlKGRhdGUpLCB5ID0gcmV0dXJucywgZ3JvdXA9c3RvY2tfbmFtZV9yb290LCBjb2xvcj1uYW1lLCBsaW5ldHlwZT1uYW1lKSkgKwogICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJDYXRlZ29yeSAtIERpdmVyc2lmaWVkIiwKICAgICAgICAgICAgICAgICAgIHggPSAicmVmZXJlbmNlIG1vbnRoIiwgeSA9ICJtb250aGx5IHN0b2NrIHJldHVybnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwPSAiVGlja2VyIiwgY29sb3I9ICJUaWNrZXIiKQpnZ3Bsb3RseShwLCB3aWR0aD04ODAsIGhlaWdodD00NTApCmBgYAoKClRvIGNhbGN1bGF0ZSB0aGUgaW5kZXggZm9yIHRoZSBjYXRlZ29yeSBJIG1vdmUgdGhlIHN0b2NrIHRpY2tlcnMgaW50byB0aGVvciAKb3duIGNvbHVtbiB3aGljaCBhbGxvd3MgZWFzaWVyIGNhbGN1bGF0aW9ucyBsYXRlciBvbi4gRWFjaCByb3cgY29ycmVzcG9uZHMKdG8gb25lIHVuaXF1ZSBtb250aApgYGB7cn0Kc3RvY2tfc2VyaWVzX2RpdiA8LSB0aWR5cjo6cGl2b3Rfd2lkZXIoZmlsdGVyKHN0b2NrX3NlcmllcywgcmVhbF9lc3RhdGVfc3ViX3NlY3RvciA9PSAiRGl2ZXJzaWZpZWQiKVssIGMoImRhdGUiLCAic3RvY2tfbmFtZV9yb290IiwgInJldHVybnMiKV0sCiAgICAgICAgICAgICAgICAgICBuYW1lc19mcm9tID0gc3RvY2tfbmFtZV9yb290LCB2YWx1ZXNfZnJvbSA9IHJldHVybnMpCgojIGVuc3VyZXMgdGhhdCBpZiBzdG9jayBpcyBub3QgYXZhaWxhYmxlIHRoaXMgbW9udGgsIHRoZXJlIGlzIGEgMApzdG9ja19zZXJpZXNfZGl2W2lzLm5hKHN0b2NrX3Nlcmllc19kaXYpXSA8LSAwCgpoZWFkKHN0b2NrX3Nlcmllc19kaXYsIDIpCmBgYAoKCmBgYHtyfQojIGdldCBtYXJrZXQgY2FwcyBmb3Igc3RvY2sgdGlja2VycyBvZiBjYXRlZ29yeS4KbWFya2V0X2NhcCA8LSBzdG9ja19zZXJpZXNfc3RhdHNfZGl2JG1hcmtldF9jYXBfX2NfX19fMzBfc2VwdGVtYmVyXzIwMjAKCmNyZWF0ZV9pbmRleF92YWx1ZSA8LSBmdW5jdGlvbih4KSB7CgogICMgY3JlYXRlIHN1bSBvZiBtYXJrZXQgY2FwIGZvciBhbGwgc3RvY2tzIGV4aXN0aW5nIHRoaXMgbW9udGgKICBtaXNzaW5nX3ZhbHVlX2ZsYWcgPC0geCAhPSAwCiAgbW9udGhseV9ub3JtX2ZhY3RvciA8LSAgc3VtKG1hcmtldF9jYXBbbWlzc2luZ192YWx1ZV9mbGFnXSkKCiAgIyBpbmRleCBhcmUgc3RvY2tzIHggd2VpZ2h0ZWQgYnkgbm9ybWFsaXplZCBtYXJrZXQgY2FwICAgCiAgbW9udGhseV9pbmRleCA8LSBzdW0oKHggKiBtYXJrZXRfY2FwKSAvIG1vbnRobHlfbm9ybV9mYWN0b3IpCiAgbW9udGhseV9pbmRleAp9CnN0b2NrX3Nlcmllc19kaXYkaW5kZXggPC0gYXBwbHkoc3RvY2tfc2VyaWVzX2RpdlssIHN0b2NrX3Nlcmllc19zdGF0c19kaXYkc3RvY2tfbmFtZV9yb290XSwgMSwgY3JlYXRlX2luZGV4X3ZhbHVlKQpgYGAKCgpgYGB7cn0KaGVhZChzdG9ja19zZXJpZXNfZGl2KQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MjQsIGZpZy5oZWlnaHQ9MTJ9CnAgPC0gZ2dwbG90KGRhdGEgPSBzdG9ja19zZXJpZXNfZGl2KSArIAogICAgICAgICAgICAgIGdlb21fbGluZShhZXMoeCA9IGFzLkRhdGUoZGF0ZSksIHkgPSBpbmRleCkpICsKICAgICAgICAgICAgICAgIGxhYnModGl0bGUgPSAiIENhdGVnb3J5IC1EaXZlcnNpZmllZCAtIEluZGV4IiwKICAgICAgICAgICAgICAgICAgIHggPSAicmVmZXJlbmNlIG1vbnRoIiwgeSA9ICJpbmRleCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXA9ICJUaWNrZXIiLCBjb2xvcj0gIlRpY2tlciIpCmdncGxvdGx5KHAsIHdpZHRoPTg4MCwgaGVpZ2h0PTQ1MCkKYGBgCgoKCmBgYHtyfQpoZWFkKHN0b2NrX3Nlcmllc19kaXYpCmBgYAoKCgoKCgoKCmBgYHtyfQpmaWx0ZXIoc3RvY2tfc2VyaWVzLCByZWFsX2VzdGF0ZV9zdWJfc2VjdG9yID09ICJEaXZlcnNpZmllZCIpCmBgYAoKCgojIyMgMi4gQ2F0ZWdvcnk6IFNwZWNpYWxpemVkCgpUaGUgY29tcGFuaWVzIHdpdGggYSBsYXJnZXN0IG1hcmtldCBjYXBpdGFsaXphdGlvbiBleGlzdCBhbHNvIHRoZSBsb25nZXN0LgpJZiB3ZSB3b3VsZCB3ZWlnaHQgYWNjb3JkaW5nIHRvIGNhcGl0YWxpemF0aW9uLCB0aGVuIG9ubHkgdHdvIGNvbXBhbmllcyB3b3VsZApkb21pbmF0ZSBhbiBjYXRlZ29yaWNhbCBpbmRpY2F0b3IuCmBgYHtyfQpzdG9ja19zZXJpZXNfc3RhdHNfc3BlYyA8LSBzdG9ja19zZXJpZXMgJT4lIAogIGZpbHRlcihyZWFsX2VzdGF0ZV9zdWJfc2VjdG9yPT0iU3BlY2lhbGl6ZWQiKSAlPiUKICBncm91cF9ieShzdG9ja19uYW1lX3Jvb3QpICU+JQogICAgICBzdW1tYXJpemUoCiAgICAgICAgbWluID0gbWluKGRhdGUsIG5hLnJtPVRSVUUpLAogICAgICAgIG1heCA9IG1heChkYXRlLCBuYS5ybT1UUlVFKSwKICAgICAgICByZWFsX2VzdGF0ZV9zdWJfc2VjdG9yID0gdW5pcXVlKHJlYWxfZXN0YXRlX3N1Yl9zZWN0b3IpLAogICAgICAgIG1hcmtldF9jYXBfX2NfX19fMzBfc2VwdGVtYmVyXzIwMjAgPSAKICAgICAgICAgIG1heChtYXJrZXRfY2FwX19jX19fXzMwX3NlcHRlbWJlcl8yMDIwKSwKICAgICAgICBuYW1lID0gdW5pcXVlKG5hbWUpLAogICAgICAgIC5ncm91cHMgPSAia2VlcCIKICAgICAgKQpzdG9ja19zZXJpZXNfc3RhdHNfc3BlYyRtYXJrZXRfY2FwX2ZyYWN0aW9uIDwtIAogIHN0b2NrX3Nlcmllc19zdGF0c19zcGVjJG1hcmtldF9jYXBfX2NfX19fMzBfc2VwdGVtYmVyXzIwMjAvc3VtKHN0b2NrX3Nlcmllc19zdGF0c19zcGVjJG1hcmtldF9jYXBfX2NfX19fMzBfc2VwdGVtYmVyXzIwMjApCnN0b2NrX3Nlcmllc19zdGF0c19zcGVjJHJlYWxfZXN0YXRlX3N1Yl9zZWN0b3IgPC0gTlVMTApzdG9ja19zZXJpZXNfc3RhdHNfc3BlYwpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MjQsIGZpZy5oZWlnaHQ9MTZ9CnAgPC0gZ2dwbG90KGRhdGEgPSBmaWx0ZXIoc3RvY2tfc2VyaWVzLCByZWFsX2VzdGF0ZV9zdWJfc2VjdG9yID09ICJTcGVjaWFsaXplZCIpKSArIAogICAgICAgICAgICAgIGdlb21fbGluZShhZXMoeCA9IGFzLkRhdGUoZGF0ZSksIHkgPSByZXR1cm5zLCBncm91cD1zdG9ja19uYW1lX3Jvb3QsIGNvbG9yPW5hbWUsIGxpbmV0eXBlPW5hbWUpKSArCiAgICAgICAgICAgICAgICBsYWJzKHRpdGxlID0gIkNhdGVnb3J5IC0gU3BlY2lhbGl6ZWQiLAogICAgICAgICAgICAgICAgICAgeCA9ICJyZWZlcmVuY2UgbW9udGgiLCB5ID0gImNsb3NlIHN0b2NrIHZhbHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cD0gIlRpY2tlciIsIGNvbG9yPSAiVGlja2VyIikKZ2dwbG90bHkocCwgd2lkdGg9ODAsIGhlaWdodD00NTApCmBgYAoKCiMjIyAzLiBDYXRlZ29yeTogUmVhbCBFc3RhdGUgRGV2ZWxvcG1lbnQgYW5kIFNlcnZpY2VzCgpBbGwgMyBjb21wYW5pZXMgZXhpc3QgZm9yIGEgbG9uZ2VyIHRpbWUgYXQgdGhlIHN0b2NrIG1hcmtldCBhbmQgaGF2ZSBhIHNpbWlsYXIKbWFya2V0IGNhcC4gT25lIGNvbXBhbnkgd291bGQgZG9taW5hdGUgYSBjYXRlZ29yaWNhbCBpbmRpY2F0b3Igd2l0aCA1MCUuCgpgYGB7cn0Kc3RvY2tfc2VyaWVzX3N0YXRzX3JlYWwgPC0gc3RvY2tfc2VyaWVzICU+JSAKICBmaWx0ZXIocmVhbF9lc3RhdGVfc3ViX3NlY3Rvcj09IlJlYWwgRXN0YXRlIERldmVsb3BtZW50IGFuZCBTZXJ2aWNlcyIpICU+JQogIGdyb3VwX2J5KHN0b2NrX25hbWVfcm9vdCkgJT4lCiAgICAgIHN1bW1hcml6ZSgKICAgICAgICBtaW4gPSBtaW4oZGF0ZSwgbmEucm09VFJVRSksCiAgICAgICAgbWF4ID0gbWF4KGRhdGUsIG5hLnJtPVRSVUUpLAogICAgICAgIHJlYWxfZXN0YXRlX3N1Yl9zZWN0b3IgPSB1bmlxdWUocmVhbF9lc3RhdGVfc3ViX3NlY3RvciksCiAgICAgICAgbWFya2V0X2NhcF9fY19fX18zMF9zZXB0ZW1iZXJfMjAyMCA9IAogICAgICAgICAgbWF4KG1hcmtldF9jYXBfX2NfX19fMzBfc2VwdGVtYmVyXzIwMjApLAogICAgICAgIG5hbWUgPSB1bmlxdWUobmFtZSksCiAgICAgICAgLmdyb3VwcyA9ICJrZWVwIgogICAgICApCnN0b2NrX3Nlcmllc19zdGF0c19yZWFsJG1hcmtldF9jYXBfZnJhY3Rpb24gPC0gCiAgc3RvY2tfc2VyaWVzX3N0YXRzX3JlYWwkbWFya2V0X2NhcF9fY19fX18zMF9zZXB0ZW1iZXJfMjAyMC9zdW0oc3RvY2tfc2VyaWVzX3N0YXRzX3JlYWwkbWFya2V0X2NhcF9fY19fX18zMF9zZXB0ZW1iZXJfMjAyMCkKc3RvY2tfc2VyaWVzX3N0YXRzX3JlYWwkcmVhbF9lc3RhdGVfc3ViX3NlY3RvciA8LSBOVUxMCnN0b2NrX3Nlcmllc19zdGF0c19yZWFsCmBgYAoKYGBge3IsIGZpZy53aWR0aD0yNCwgZmlnLmhlaWdodD0xNH0KcCA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihzdG9ja19zZXJpZXMsIHJlYWxfZXN0YXRlX3N1Yl9zZWN0b3IgPT0gIlJlYWwgRXN0YXRlIERldmVsb3BtZW50IGFuZCBTZXJ2aWNlcyIpKSArIAogICAgICAgICAgICAgIGdlb21fbGluZShhZXMoeCA9IGFzLkRhdGUoZGF0ZSksIHkgPSByZXR1cm5zLCBncm91cD1zdG9ja19uYW1lX3Jvb3QsIGNvbG9yPW5hbWUsIGxpbmV0eXBlPW5hbWUpKSArCiAgICAgICAgICAgICAgICBsYWJzKHRpdGxlID0gIkNhdGVnb3J5IC0gUmVhbCBFc3RhdGUgRGV2ZWxvcG1lbnQgYW5kIFNlcnZpY2VzIiwKICAgICAgICAgICAgICAgICAgIHggPSAicmVmZXJlbmNlIG1vbnRoIiwgeSA9ICJjbG9zZSBzdG9jayB2YWx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXA9ICJUaWNrZXIiLCBjb2xvcj0gIlRpY2tlciIpCmdncGxvdGx5KHAsIHdpZHRoPTc4MCwgaGVpZ2h0PTQ1MCkKYGBgCgoKIyMjIDQuIENhdGVnb3J5OiBJbmR1c3RyaWFsL09mZmljZS9SZXRhaWwvUmVzaWRlbnRpYWwKCmBgYHtyfQpzdG9ja19zZXJpZXNfc3RhdHNfaW5kIDwtIHN0b2NrX3NlcmllcyAlPiUgCiAgZmlsdGVyKHJlYWxfZXN0YXRlX3N1Yl9zZWN0b3I9PSJJbmR1c3RyaWFsL09mZmljZS9SZXRhaWwvUmVzaWRlbnRpYWwiKSAlPiUKICBncm91cF9ieShzdG9ja19uYW1lX3Jvb3QpICU+JQogICAgICBzdW1tYXJpemUoCiAgICAgICAgbWluID0gbWluKGRhdGUsIG5hLnJtPVRSVUUpLAogICAgICAgIG1heCA9IG1heChkYXRlLCBuYS5ybT1UUlVFKSwKICAgICAgICByZWFsX2VzdGF0ZV9zdWJfc2VjdG9yID0gdW5pcXVlKHJlYWxfZXN0YXRlX3N1Yl9zZWN0b3IpLAogICAgICAgIG1hcmtldF9jYXBfX2NfX19fMzBfc2VwdGVtYmVyXzIwMjAgPSAKICAgICAgICAgIG1heChtYXJrZXRfY2FwX19jX19fXzMwX3NlcHRlbWJlcl8yMDIwKSwKICAgICAgICAuZ3JvdXBzID0gImtlZXAiCiAgICAgICkKc3RvY2tfc2VyaWVzX3N0YXRzX2luZCRtYXJrZXRfY2FwX2ZyYWN0aW9uIDwtIAogIHN0b2NrX3Nlcmllc19zdGF0c19pbmQkbWFya2V0X2NhcF9fY19fX18zMF9zZXB0ZW1iZXJfMjAyMC9zdW0oc3RvY2tfc2VyaWVzX3N0YXRzX2luZCRtYXJrZXRfY2FwX19jX19fXzMwX3NlcHRlbWJlcl8yMDIwKQpzdG9ja19zZXJpZXNfc3RhdHNfaW5kJHJlYWxfZXN0YXRlX3N1Yl9zZWN0b3IgPC0gTlVMTApzdG9ja19zZXJpZXNfc3RhdHNfaW5kCmBgYAoKVG9wIGNvbXBhbmllcyBpbiBjb21wYW55IGZvciBtYXJrZXQgY2FwIGluZGljYXRlcyB0aGF0IHRoZSBtYXJrZXQgY2FwIGlzIGZhaXJseQpkaXN0cmlidXRlZCBhbmQgdGhlcmUgbWF5IGJlIGEgbGVzcyBkZXBlbmRlbmN5IG9mIGEgY2F0ZWdvcmljYWwgaW5kaWNhdG9yIG9uCmluZGl2aWR1YWwgY29tcGFuaWVzLgpgYGB7cn0KCmhlYWQoc3RvY2tfc2VyaWVzX3N0YXRzX2luZCAlPiUgYXJyYW5nZShhY3Jvc3MobWFya2V0X2NhcF9mcmFjdGlvbiwgZGVzYykpLCAxMCkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTI0LCBmaWcuaGVpZ2h0PTEyfQpwIDwtIGdncGxvdChkYXRhID0gZmlsdGVyKHN0b2NrX3NlcmllcywgcmVhbF9lc3RhdGVfc3ViX3NlY3RvciA9PSAiSW5kdXN0cmlhbC9PZmZpY2UvUmV0YWlsL1Jlc2lkZW50aWFsIikpICsgCiAgICAgICAgICAgICAgZ2VvbV9saW5lKGFlcyh4ID0gYXMuRGF0ZShkYXRlKSwgeSA9IHJldHVybnMsIGdyb3VwPXN0b2NrX25hbWVfcm9vdCwgY29sb3I9bmFtZSwgbGluZXR5cGU9bmFtZSkpICsKICAgICAgICAgICAgICAgIGxhYnModGl0bGUgPSAiQ2F0ZWdvcnkgLSBJbmR1c3RyaWFsL09mZmljZS9SZXRhaWwvUmVzaWRlbnRpYWwiLAogICAgICAgICAgICAgICAgICAgeCA9ICJyZWZlcmVuY2UgbW9udGgiLCB5ID0gImNsb3NlIHN0b2NrIHZhbHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cD0gIlRpY2tlciIsIGNvbG9yPSAiVGlja2VyIikKZ2dwbG90bHkocCwgd2lkdGg9ODgwLCBoZWlnaHQ9NDUwKQpgYGAKCgojIyA1LiBBbGwgQ2F0ZWdvcmllcwoKYGBge3J9CnN0b2NrX3Nlcmllc19zdGF0c19hbGwgPC0gc3RvY2tfc2VyaWVzICU+JSAKICBncm91cF9ieShzdG9ja19uYW1lX3Jvb3QpICU+JQogICAgICBzdW1tYXJpemUoCiAgICAgICAgbWluID0gbWluKGRhdGUsIG5hLnJtPVRSVUUpLAogICAgICAgIG1heCA9IG1heChkYXRlLCBuYS5ybT1UUlVFKSwKICAgICAgICByZWFsX2VzdGF0ZV9zdWJfc2VjdG9yID0gdW5pcXVlKHJlYWxfZXN0YXRlX3N1Yl9zZWN0b3IpLAogICAgICAgIG1hcmtldF9jYXBfX2NfX19fMzBfc2VwdGVtYmVyXzIwMjAgPSAKICAgICAgICAgIG1heChtYXJrZXRfY2FwX19jX19fXzMwX3NlcHRlbWJlcl8yMDIwKSwKICAgICAgICAuZ3JvdXBzID0gImtlZXAiCiAgICAgICkKc3RvY2tfc2VyaWVzX3N0YXRzX2FsbCRtYXJrZXRfY2FwX2ZyYWN0aW9uIDwtIAogIHN0b2NrX3Nlcmllc19zdGF0c19hbGwkbWFya2V0X2NhcF9fY19fX18zMF9zZXB0ZW1iZXJfMjAyMC9zdW0oc3RvY2tfc2VyaWVzX3N0YXRzX2FsbCRtYXJrZXRfY2FwX19jX19fXzMwX3NlcHRlbWJlcl8yMDIwKQpzdG9ja19zZXJpZXNfc3RhdHNfYWxsJHJlYWxfZXN0YXRlX3N1Yl9zZWN0b3IgPC0gTlVMTApzdG9ja19zZXJpZXNfc3RhdHNfYWxsCmBgYAoKCkZhaXJseSB3ZWxsIGRpc3RyaWJ1dGVkLgpgYGB7cn0KaGVhZChzdG9ja19zZXJpZXNfc3RhdHNfYWxsICU+JSBhcnJhbmdlKGFjcm9zcyhtYXJrZXRfY2FwX2ZyYWN0aW9uLCBkZXNjKSksIDEwKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MjQsIGZpZy5oZWlnaHQ9MTJ9CnAgPC0gZ2dwbG90KGRhdGEgPSBzdG9ja19zZXJpZXMpICsgCiAgICAgICAgICAgICAgZ2VvbV9saW5lKGFlcyh4ID0gYXMuRGF0ZShkYXRlKSwgeSA9IHJldHVybnMsIGdyb3VwPXN0b2NrX25hbWVfcm9vdCwgYWxwaGE9MC4yKSkgKwogICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9ICJBbGwgdGlja2VycyIsCiAgICAgICAgICAgICAgICAgICB4ID0gInJlZmVyZW5jZSBtb250aCIsIHkgPSAiY2xvc2Ugc3RvY2sgdmFsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwPSAiVGlja2VyIiwgY29sb3I9ICJUaWNrZXIiKQpnZ3Bsb3RseShwLCB3aWR0aD04ODAsIGhlaWdodD00NTApCmBgYAoKCgoKCgoK